// definition of the function prototypes in basic_types.h

// checks if a pointer is valid for read/write
owl_bool owl_check_ptr(void * ptr, owl_umax size)
{
  return (ptr != NULL && size != 0);
}

// print the bits of a byte in memory
owl_umax owl_print_byte_bin(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false)
    return 0;
  owl_byte tmp = 0x80;
  printf("0b");
  for (owl_umax i = 0; i < OWL_BYTE_BITS; i++) {
    printf("%u", (*mem & tmp) >> (OWL_BYTE_BITS - i - 1));
    tmp = tmp >> 1;
  }
  return sizeof(owl_byte);
}

// print byte contents in decimal
owl_umax owl_print_byte_dec(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false)
    return 0;
  printf("%u", *mem);
  return sizeof(owl_byte);
}

// print byte contents in hexadecimal
owl_umax owl_print_byte_hex(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false)
    return 0;
  printf("0x%02X", *mem);
  return sizeof(owl_byte);
}

// print char contents in decimal (signed integer 8 bits)
owl_umax owl_print_char_dec(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false)
    return 0;
  printf("%d", *mem);
  return sizeof(owl_char);
}

// print char contents as ascii
owl_umax owl_print_char_char(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false)
    return 0;
  if (*mem >= 0 && *mem <= 127)
    printf("%c", *mem);
  else
    printf("UNDEF_CHAR");
  return sizeof(owl_char);
}

// print umax integer as decimal
owl_umax owl_print_umax_dec(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false || mem_size < sizeof(owl_umax))
    return 0;
  printf("%llu", ((owl_umax *) mem)[0]);
  return sizeof(owl_umax);
}

// print umax integer as hexadecimal
owl_umax owl_print_umax_hex(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false || mem_size < sizeof(owl_umax))
    return 0;
  printf("0x%llX", ((owl_umax *) mem)[0]);
  return sizeof(owl_umax);
}

// print smax integer as decimal
owl_umax owl_print_smax_dec(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false || mem_size < sizeof(owl_smax))
    return 0;
  printf("%lld", ((owl_smax *) mem)[0]);
  return sizeof(owl_smax);
}

// print fmax number
owl_umax owl_print_fmax(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false || mem_size < sizeof(owl_fmax))
    return 0;
  printf("%lf", ((owl_fmax *) mem)[0]);
  return sizeof(owl_fmax);
}

// print bool (number)
owl_umax owl_print_bool(owl_byte * mem, owl_umax mem_size)
{
  // check params
  if (owl_check_ptr(mem, mem_size) == owl_false || mem_size < sizeof(owl_bool))
    return 0;
  if (*mem == 0)
    printf("false");
  else
    printf("true");
  return sizeof(owl_bool);
}

// to compare bytes
owl_char owl_comp_byte(owl_byte * byte1, owl_byte * byte2)
{
  // check params
  if (byte1 == NULL || byte2 == NULL)
    return owl_comp_err;
  // do the comparison
  if (*byte1 < *byte2)
    return owl_comp_less;
  else if (*byte1 > *byte2)
    return owl_comp_greater;
  return owl_comp_equal;
}

// to compare chars
owl_char owl_comp_char(owl_byte * char1, owl_byte * char2)
{
  // check params
  if (char1 == NULL || char2 == NULL)
    return owl_comp_err;
  // do the comparison
  if (*char1 < *char2)
    return owl_comp_less;
  else if (*char1 > *char2)
    return owl_comp_greater;
  return owl_comp_equal;
}

// to compare umaxes
owl_char owl_comp_umax(owl_byte * umax1, owl_byte * umax2)
{
  // check params
  if (umax1 == NULL || umax2 == NULL)
    return owl_comp_err;
  // do the comparison
  owl_umax * tmp1 = (void *) umax1,
           * tmp2 = (void *) umax2;
  if (*tmp1 < *tmp2)
    return owl_comp_less;
  else if (*tmp1 > *tmp2)
    return owl_comp_greater;
  return owl_comp_equal;
}

// to compare smaxes
owl_char owl_comp_smax(owl_byte * smax1, owl_byte * smax2)
{
  // check params
  if (smax1 == NULL || smax2 == NULL)
    return owl_comp_err;
  // do the comparison
  owl_smax * tmp1 = (void *) smax1,
           * tmp2 = (void *) smax2;
  if (*tmp1 < *tmp2)
    return owl_comp_less;
  else if (*tmp1 > *tmp2)
    return owl_comp_greater;
  return owl_comp_equal;
}

// to compare fmaxes
owl_char owl_comp_fmax(owl_byte * fmax1, owl_byte * fmax2)
{
  // check params
  if (fmax1 == NULL || fmax2 == NULL)
    return owl_comp_err;
  // do the comparison
  owl_fmax * tmp1 = (void *) fmax1,
           * tmp2 = (void *) fmax2;
  if (*tmp1 < *tmp2)
    return owl_comp_less;
  else if (*tmp1 > *tmp2)
    return owl_comp_greater;
  return owl_comp_equal;
}


// to compare bools
owl_char owl_comp_bool(owl_byte * bool1, owl_byte * bool2)
{
  // reuse owl_comp_byte
  return owl_comp_byte(bool1, bool2);
}
